/**
 * @file mq_mgr.cpp
 * @brief mq客户端封装，以单例的形式对外提供订阅发布功能。
 *
 *用josdk的订阅发布进行封装，线程安全
 * 
 * @author ypj
 * @date 2023年11月6日
 * @license MIT Apache2.0
 * Copyright (C), 2010-2023 Jouav Co., Ltd.
 */
#include "mq_mgr.h"
#include "log.h"

namespace jouav
{
/*!
 * @brief 单例接口获取MQMgr的实例化对象
 * @return MQMgr实例化对象
 */
MQMgr& MQMgr::GetInstance()
{
    static MQMgr mq_mgr;
    return mq_mgr;
}

/**
 * @brief MQ初始化
 * @param strip 输入：MQ服务器IP，默认127.0.0.1
 * @return 0:成功 -1:失败
 */
int MQMgr::Init(std::string strip)
{
    if (init_flag == true)
    { //防止被重复初始化
        log_sys->info("MQMgr::Init already, return.");
        return 0;
    }
    char str[256] = {0};
    snprintf(str, sizeof str, R"({"target":{"ip":"%s"}})", strip.c_str());
    uav_env_ = jo_sdk::env_create(str);

    int ret = jo_sdk::get_user_access(uav_env_, "jouav");
    if (ret)
    {
        log_sys->error("MQMgr::Init get_user_access failed. ret {}", ret);
        return ret;
    }

    com_t_ = jo_sdk::create_com_raw(uav_env_);
    init_flag = true;
    log_sys->info("MQMgr::Init success");
    return 0;
}

/*!
 * @brief 添加订阅
 * @param topic_ 输入：订阅主题
 * @param func_ 输入：回调函数
 * @return int: 0:没有错误 -1:内部错误 65535：没有授权
 * @note 回调函数返回
 */
int MQMgr::Subscribe(const std::string& topic_, sub_cb func_)
{
    int fd = com_t_->subscribe(topic_, func_);
    if (fd != 65535 && fd > 0)
    {
        std::lock_guard<std::recursive_mutex> lock(mutex_);
        map_sub_fd_[topic_] = fd;
        return 0;
    }
    return fd;
}
/*!
 * @brief 取消订阅
 * @param topic_ 输入：取消订阅的Topic
 * @return int: 0:没有错误 -1:内部错误 65535：没有授权
 */
int MQMgr::UnSubscribe(const std::string& topic_)
{
    auto it = map_sub_fd_.find(topic_);
    int ret = 0; 
    if (it != map_sub_fd_.end())
    {
        ret = com_t_->unsubscribe(it->second);
        std::lock_guard<std::recursive_mutex> lock(mutex_);
        map_sub_fd_.erase(it);
    }
    return ret;

}

/*!
 * @brief 发布消息
 * @param topic_ 输入：发布主题
 * @param data_ 输入：数据
 * @param len_ 输入：长度 ，-1失败
 * @return int: 0:没有错误 -1:内部错误 65535：没有授权
 */
int MQMgr::Publish(const std::string& topic_, const void* data_, size_t len_)
{
    char buf[1024] = { 0 };
    int pos = 0;
    for (size_t idx = 0; idx < len_; idx++)
    {
        pos += snprintf(buf + pos, 1024, "%02x ", ((const char*)data_)[idx]);
    }
    std::string log = "topic:" + topic_ + "\n" + buf;
    log_sys->info("{}", log);
    return com_t_->publish(topic_, data_, len_);
}


}// namespace jouav
